題目要求:
這題目要找到將字串 word1 轉換成 word2 所需的最少編輯次數操作有三種:
插入一個字元。
刪除一個字元。
替換一個字元。
思路:
這題的重點是 動態規劃 ,要用一個 DP 表來追蹤每步的轉換操作次數。
思考問題:
如果兩個字串的長度為 m 和 n,可以建一個大小 (m+1) x (n+1) 的 DP 表 dp, dp[i][j] 表示把 word1 的前 i 個字母換成 word2 的前 j 個字母需要的最小操作次數。
初始條件:
i = 0 時,表示 word1 是空字串,要把它轉成 word2,要插入 j 個字元,所以 dp[0][j] = j,j = 0 時,表示 word2 是空字串,要把它轉成 word1,要刪除 i 個字元,所以 dp[i][0] = i。
狀態轉移方程:
word1[i-1] == word2[j-1],就不用替換,所以 dp[i][j] = dp[i-1][j-1],如果word1[i-1] != word2[j-1],就有三種可能的操作:
插入:從 dp[i][j-1] 加 1。
刪除:從 dp[i-1][j] 加 1。
替換:從 dp[i-1][j-1] 加 1。
所以,dp[i][j] 取這三個的最小值。
動態規劃的過程:
初始化 DP 表,依據狀態轉移方程填充 DP 表,最後的答案就是 dp[m][n],也就是word1 的全部字母轉成 word2 所要的最少操作次數。
程式碼:
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
#取兩個字串的長度
m, n = len(word1), len(word2)
#建立DP 表,大小為 (m+1) x (n+1)
dp = [[0] * (n + 1) for _ in range(m + 1)]
#初始化 DP 表的第一列和第一行
for i in range(1, m + 1):
dp[i][0] = i # 刪除
for j in range(1, n + 1):
dp[0][j] = j # 插入
#動態規劃填 DP 表
for i in range(1, m + 1):
for j in range(1, n + 1):
if word1[i - 1] == word2[j - 1]:
# 當字母相同,不需要操作
dp[i][j] = dp[i - 1][j - 1]
else:
# 字母不同,取插入、刪除、替換操作的最小值 + 1
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
#結果在 dp[m][n] 中
return dp[m][n]
解釋:
初始化,dp[i][0] = i 表示把 word1 的前 i 個字母換成空字串,操作;刪除 i 個字母 ,dp[0][j] = j 表示把空字串轉成 word2 的前 j 個字母,就插入 j 個字母。
遞推公式:
word1[i-1] == word2[j-1],兩個字元同,不用編輯,dp[i][j] = dp[i-1][j-1],如果字元不同,就可以選擇 插入、刪除 或 替換 操作,再取這三個操作的最小值加一次操作次數,結果,dp[m][n] 就是把word1 完全轉成 word2 要最少操作次數。
簡言之:
初始化 DP 表,建大小為 (m+1) x (n+1) 的 DP 表,初始化第一行和第一列,分別對應插入和刪除,動態轉移,從 word1 的第一個字開始,逐步比較每個字母,再根據匹配情況做狀態轉移,返回結果,DP 表的右下角就是我要的最少操作次數。
時間和空間複雜度:
時間複雜度:O(m * n),因為填充一個大小為是(m+1) x (n+1) 的 DP 表,空間複雜度:O(m * n),一個大小是 (m+1) x (n+1) 的 DP 表存儲結果。
這樣就可以解決這個問題,算從一個字串換到另一個字串的最小編輯操作次數。